#!/bin/sh
# -*-tcl-*-
#****h* tkjmdict/tkjmdict
# NAME
#  tkjmdict $Revision: 1.7 $
# COPYRIGHT
#  (c) 2000-2003 Petteri Kettunen -- http://www.iki.fi/petterik/
# SYNOPSIS
#  tkjmdict [options]
#
#  You may have to modify wish startup parameters depending on your system.
#  See startup_wish for examples.
# OPTIONS
#  -lang     specify language to be loaded in the startup
#  -parse    specify JMdict file to be parsed for new dictionary files
# EXAMPLE
#  Start with German dictionary loaded:
#    tkjmdict -lang de
#  Parse JMdict XML file in order to generate new dictionary files:
#    tclsh tkjmdict -parse JMdict
# USES
#   - Tcl/Tk version 8.5 or higher -- http://tcl.activestate.com/
#   - XML parser depends on tDOM -- http://tdom.github.com/
#     This is not needed unless you want to parse the dictionaries yourself
#   - JMdict -- http://www.csse.monash.edu.au/~jwb/jmdict.html
# MODIFICATION HISTORY
#  v0.95/2012
#    - Use tDOM parser and update parsing of new JMdict format
#    - removed saveTextAs and insertFile
#  v0.94/2003-07-06:
#    - JMdict V2003-03 10 June
#  v0.93/2003-02-xx:
#    - check /usr/share/tkjmdict for dict files
#    - specfile and RPM build rules RH8.0/rpmbuild
#    - Development starting again after too long dormant state with
#      ActiveTcl 8.3.5 (Tcl-XML 2.4) and Jim's dict released Feb 4 2003.
#    - XML parsing rewritten, whole library is parsed in one go.
#    - New languages: French and Russian
#    - TkJMdict renamed to tkjmdict
#  v0.92/2001-12-31: XML parsing partly rewritten and tested with tclxml-2.0
#  v0.91/2001-12-26: Bugs reported by B. So fixed, splash screen modified,
#    default font set to Osaka on Darwin, wish startup on Darwin 
#   (startup_wish), RoboDoc headers
#  v0.90/2000-04-02: Initial release developed on Tcl/Tk 8.3.2
# BUGS
#  plenty
# NOTES
#  Documentation by RoboDoc http://sourceforge.net/projects/robodoc/  
#******

#****f* tkjmdict/startup_wish
# NAME
#  startup_wish
# NOTES
#  The default setup is for Mac OS X. Modify below if needed.
# SOURCE
#
# GNU/Linux and UNIX - this is ok for ordinary runtime: start wish \
exec wish "$0" "$@"
# Recommended: use ActiveTcl from http://tcl.activestate.com/ \
#exec /usr/local/ActiveTcl/bin/wish "$0" "$@"
# Mac OS X: start Wish.App \
# exec '/Users/petterik/Applications/Wish Shell.app/Contents/MacOS/Wish Shell' "$0" "$@" 
# Wintel: system should find the righ binary based on .tcl extension
#****** 

#****f* tkjmdict/namespace_init
# NAME
#  namespace_init
# DESCRIPTION
#  Namespace initialisation and internal variables
# SOURCE
#
namespace eval ::jmdict {
	# FIXME read log
    set vers 0.95
    set jmdictVer {undefined}
    set freeWrap 0
    set debug 0 ;# affects parsing only
    set ptr 0
    set elem 0
    set inp {}
	# max number of entries parsed from xml, set to zero for unlimited
    set maxEntries 0
	# maximum number of matches displayed from search
    set maxMatches 200
    set matches {}
    set searchN 0
    set searchT 0
    set loadT 0
    set sflg 0
    set parseAll 1
    set langs {eng ger fre rus} ; # these are updated manually (ugly)
    set langPtr 0 ;# points to eng in langs
    set g_lang [lindex $langs $langPtr]
    array set langNames {eng English ger Deutsch fre Fran\u00E7ais rus \u0420\u043E\u0441\u0441\u0438\u044F}
    set newLang 0
    set dictDir {} ;# where dictionaries are stored
    set dir {}
    set availableDicts {}
}
#******

#****f* tkjmdict/initUIVars
# NAME
#  initUIVars
# DESCRIPTION
#  Init variables and data that are needed in GUI.
#  Tk is not needed to parse the dictionaries.
# SOURCE
#
proc ::jmdict::initUIVars {} {
    namespace eval ::jmdict {
    	variable ::tcl_platform
    	
		set textRows 16
		set textCols 50
		set maxFontChars 0
		set fontSize 12
		set newFontSize 12
		switch -- $tcl_platform(os) {
			Darwin {set textFont Osaka}
			Linux {set textFont Times}
			default {set textFont {Courier New}}
		}
		set font [list $textFont $fontSize {normal}]
		set fonts [lsort [font families]]
		foreach i $fonts {
			if {[string length $i] > $maxFontChars} {
				set maxFontChars [string length $i]
			}
		}
		set busy 0
		# basic hiragana keys
		array set kb0 \
			{0,0 \u3042 0,1 \u304B 0,2 \u3055 0,3 \u305F 0,4 \u306A \
				 0,5 \u306F 0,6 \u307E 0,7 \u3084 0,8 \u3089 0,9 \u308F \
				 0,10 \u0000 1,0 \u3044 1,1 \u304D 1,2 \u3057 1,3 \u3061 \
				 1,4 \u306B 1,5 \u3072 1,6 \u307F 1,7 \u3044 1,8 \u308A \
				 1,9 \u3090 1,10 \u0000 2,0 \u3046 2,1 \u304F 2,2 \u3059 \
				 2,3 \u3064 2,4 \u306C 2,5 \u3075 2,6 \u3080 2,7 \u3086 \
				 2,8 \u308B 2,9 \u3046 2,10 \u3063 3,0 \u3048 3,1 \u3051 \
				 3,2 \u305B 3,3 \u3066 3,4 \u306D 3,5 \u3078 3,6 \u3081 \
				 3,7 \u3048 3,8 \u308C 3,9 \u3091 3,10 \u0000 4,0 \u304A \
				 4,1 \u3053 4,2 \u305D 4,3 \u3068 4,4 \u306E 4,5 \u307B \
				 4,6 \u3082 4,7 \u3088 4,8 \u308D 4,9 \u3092 4,10 \u3093 \
				 5,0 \u0000 5,1 \u0000 5,2 \u0000 5,3 \u0000 5,4 \u0000 \
				 5,5 \u0000 5,6 \u0000 5,7 \u0000 5,8 \u0000 5,9 \u0000 \
				 5,10 \u0000}
		array set kb1 \
			{0,0 \u3041 0,1 \u304C 0,2 \u3056 0,3 \u3060 0,4 \u0000 \
				 0,5 \u3070 0,6 \u3071 0,7 \u3083 0,8 \u0000 0,9 \u308E \
				 0,10 \u0000 1,0 \u3043 1,1 \u304E 1,2 \u3058 1,3 \u0000 \
				 1,4 \u0000 1,5 \u3073 1,6 \u3074 1,7 \u0000 1,8 \u0000 \
				 1,9 \u0000 1,10 \u0000 2,0 \u3045 2,1 \u3050 2,2 \u305A \
				 2,3 \u3065 2,4 \u0000 2,5 \u3076 2,6 \u3077 2,7 \u3085 \
				 2,8 \u0000 2,9 \u0000 2,10 \u0000 3,0 \u3047 3,1 \u3052 \
				 3,2 \u305C 3,3 \u3067 3,4 \u0000 3,5 \u3079 3,6 \u307A \
				 3,7 \u0000 3,8 \u0000 3,9 \u0000 3,10 \u0000 4,0 \u3049 \
				 4,1 \u3054 4,2 \u305E 4,3 \u3069 4,4 \u0000 4,5 \u307C \
				 4,6 \u307D 4,7 \u3087 4,8 \u0000 4,9 \u0000 4,10 \u0000 \
				 5,0 \u0000 5,1 \u0000 5,2 \u0000 5,3 \u0000 5,4 \u0000 \
				 5,5 \u0000 5,6 \u0000 5,7 \u0000 5,8 \u0000 5,9 \u0000 \
				 5,10 \u0000}
		# rows 0-2 cols: kya, sha, cha, nya, hya, mya, rya 
		# rows 3-5 cols: gya, za, ja, nya, hya, mya, rya
		array set kb2 \
			{0,0 \u0000 0,1 \u304D\u3083 0,2 \u3057\u3083 \
				 0,3 \u3061\u3083 0,4 \u306B\u3083 0,5 \u3072\u3083 \
				 0,6 \u0000 0,7 \u307F\u3083 0,8 \u308A\u3083 0,9 \u0000 \
				 0,10 \u0000 1,0 \u0000 1,1 \u304D\u3085 1,2 \u3057\u3085 \
				 1,3 \u3061\u3085 1,4 \u306B\u3085 1,5 \u3072\u3085 \
				 1,6 \u0000 1,7 \u307F\u3085 1,8 \u308A\u3085 1,9 \u0000 \
				 1,10 \u0000 2,0 \u0000 2,1 \u304D\u3087 2,2 \u3057\u3087 \
				 2,3 \u3061\u3087 2,4 \u306B\u3087 2,5 \u3072\u3087 2,6 \u0000 \
				 2,7 \u307F\u3087 2,8 \u308A\u3087 2,9 \u0000 2,10 \u0000 \
				 3,0 \u304E\u3083 3,0 \u0000 3,1 \u304E\u3083 3,2 \u3058\u3083 \
				 3,3 \u3062\u3083 3,4 \u0000 3,5 \u3073\u3083 3,6 \u3074\u3083 \
				 3,7 \u0000 3,8 \u0000 3,9 \u0000 3,10 \u0000 4,0 \u0000 \
				 4,1 \u304E\u3085 4,2 \u3058\u3085 4,3 \u3062\u3085 \
				 4,4 \u0000 4,5 \u3073\u3085 4,6 \u3074\u3085 4,7 \u0000 \
				 4,8 \u0000 4,9 \u0000 4,10 \u0000 5,0 \u0000 5,1 \u304E\u3087 \
				 5,2 \u3058\u3087 5,3 \u3062\u3087 5,4 \u0000 5,5 \u3073\u3087 \
				 5,6 \u3074\u3087 5,7 \u0000 5,8 \u0000 5,9 \u0000 5,10 \u0000}
		# katakana
		foreach {a1 a2} {kb0 kb3 kb1 kb4} {
			foreach i [array names $a1] {
				eval "scan \$${a1}($i) %c val"
				if {$val} {
					eval "set ${a2}($i) \\u[format %04X [expr {$val + 96}]]"
				} else {
					eval "set ${a2}($i) \\u0000"
				}
			}
		}
		set kb4(2,9) \u30F4 ;# katakana wa + ''
		set kb4(0,10) \u30F5 ;# small katakana ka
		set kb4(3,10) \u30F6 ;# small katakana ke
		# this array has two letters per entry
		foreach i [array names kb2] {
			foreach c [split $kb2($i) {}] { 
				scan $c %c val
				if {$val} {
					eval "append kb5($i) \\u[format %04X [expr {$val + 96}]]"
				} else {
					eval "set kb5($i) \\u0000"
				}
			}
		}
		# default to basic hiragana
		array set kb [array get kb0]
		set kbid 0
		if {[info exists ::env(HOME)]} {
			set dir $env(HOME)
		}
    }
}
#******


#****f* tkjmdict/showStatistics
# NAME
#  showStatistics
# SOURCE
#
proc ::jmdict::showStatistics {} {
    variable ::jmdict::searchT
    variable ::jmdict::searchN
    variable ::jmdict::loadT
    variable ::jmdict::availableDicts
    variable ::jmdict::langPtr
    global tcl_platform
    global _freewrap_contents
    global _freewrap_package

    .t delete 1.0 end    
    .t insert end "[lindex $availableDicts $langPtr]\
	    load time: [expr {$loadT/1000000.0}]\n"
    if {$searchN > 0} {    
		.t insert end "searches    : $searchN\n"
		.t insert end \
			"average time: [expr {$searchT/(1000000.0 * $searchN)}]\n" 
    }
    .t insert end "Tcl version [info patchlevel]\n"
    .t insert end "$tcl_platform(os) $tcl_platform(osVersion)\n"
    .t insert end "[info nameofexecutable]\n"
    .t insert end "$::jmdict::dictDir\n"
    if {[info exists _freewrap_contents]} {
		foreach i $_freewrap_contents {
			.t insert end $i\n
		}
    }
    if {[array exists _freewrap_package]} {
		foreach i [array names _freewrap_package] {
			.t insert end $i\n
		}
    }
}
#******

#****f* tkjmdict/posWin
# NAME
#  posWin
# SOURCE
#
proc ::jmdict::posWin {w {arg ""}} {
    switch -- $arg {
	kb {
	    # position Kana Board window just below the main application frame
	    wm geometry $w +[expr {[winfo x .] + 50}]+[expr \
		    {[winfo y .] + [winfo height .] + 35}]
	}
	default {
	    # position other child window
	    wm geometry $w +[expr {[winfo x .] + 40}]+[expr \
		    {[winfo y .] + 40}]
	}
    }
    update
}
#******

#****f* tkjmdict/selectFont
# NAME
#  selectFont
# SOURCE
#
proc ::jmdict::selectFont {} {
    variable ::jmdict::fonts
    variable ::jmdict::font

    set w .fonts
    catch {destroy $w}
    toplevel $w
    wm title $w "Select Font"
    wm iconname $w "Select Font"
    frame $w.frame -borderwidth .5c
    pack $w.frame -side top -expand yes -fill y
    scrollbar $w.frame.scroll -command "$w.frame.list yview"
    listbox $w.frame.list -yscroll "$w.frame.scroll set" \
	    -setgrid 1 -height 12 \
	    -width [expr {$::jmdict::maxFontChars + 1}] -bg white
    pack $w.frame.scroll -side right -fill y
    pack $w.frame.list -side left -expand 1 -fill both
    frame $w.buttons
    pack $w.buttons -side bottom -fill x -pady 2m
    button $w.buttons.cancel -text Cancel -command {
	catch {destroy .fonts}
    }
    button $w.buttons.ok -text OK -command {
	if {[.fonts.frame.list curselection] != ""} { 
	    set ::jmdict::textFont [lindex $::jmdict::fonts \
		    [.fonts.frame.list curselection]]
	    ::jmdict::changeFont
	    catch {destroy .fonts}
	}
    }
    pack $w.buttons.cancel $w.buttons.ok -side left -expand 1 
    foreach i $fonts {
	$w.frame.list insert end $i
    }
    bind $w.frame.list <Double-1> {
	set ::jmdict::textFont [lindex $::jmdict::fonts \
		[.fonts.frame.list curselection]]
	::jmdict::changeFont
	catch {destroy .fonts}
    }
    bind .fonts <Escape> {catch {destroy .fonts}}
    set i [lsearch -exact $fonts [lindex $font 0]]
    $w.frame.list selection set $i
    $w.frame.list see $i
    ::jmdict::posWin .fonts
    focus -force $w
}
#******

#****f* tkjmdict/changeFont
# NAME
#  changeFont
# DESCRIPTION
#  Called if the value of newFontSize is changed (trace-triggered  event)
# SEE ALSO
#  activateTraces
# SOURCE
#
proc ::jmdict::changeFont {args} {
    variable ::jmdict::fontSize
    variable ::jmdict::newFontSize
    variable ::jmdict::textFont
    variable ::jmdict::font
    if {[llength $args] && [lindex $args 0] == "::jmdict::newFontSize" && \
	    $newFontSize == $fontSize} {
	return
    } 
    set fontSize $newFontSize
    set font [list $textFont $fontSize {normal}]
    .t configure -font $font
    .inp.e configure -font $font
    update idletasks
}
#******

#****f* tkjmdict/changeLang
# NAME
#  changeLang
# FUNCTION
#  Reset variables and load a new dictionary.
# SOURCE
#
proc ::jmdict::changeLang {args} {
    if {$::jmdict::langPtr == $::jmdict::newLang} {
		return
    }
    catch {unset ::jmdict::reb}
    catch {unset ::jmdict::keb}
    catch {unset ::jmdict::gloss}
    set ::jmdict::langPtr $::jmdict::newLang
    ::jmdict::dictRead [lindex $::jmdict::langs $::jmdict::langPtr]
    # Noticed that text widget refresh is needed after changing lang.
    # This problem appeared w/ RH8.0. It shouldn't be like this but...
    after idle ::jmdict::changeFont
}
#******

#****f* tkjmdict/showNotice
# NAME
#  showNotice
# NOTES
#  This piece of code is copied and modified from Visual Tcl (vTcl:splash)
# SOURCE
#
proc ::jmdict::showNotice {msg {nx 200} {ny 250}} {
    toplevel .notice -bd 3 -relief raised
    wm withdraw .notice
    set sw [winfo screenwidth .]
    set sh [winfo screenheight .]
    wm overrideredirect .notice 1
    label .notice.l -text "$msg" -bd 1 -justify left \
	    -wraplength [expr {$nx - 40}] -font {{Courier} 10}
    pack .notice.l -side top -expand 1 -fill both -padx 20 -pady 20
    set x [expr {($sw - $nx)/2}]
    set y [expr {($sh - $ny)/2}]
    wm geometry .notice +$x+$y
    wm deiconify .notice
    update idletasks
    bind .notice <Escape> {catch {destroy .notice}}
    bind .notice <1> {catch {destroy .notice}}
}
#******

#****f* tkjmdict/about
# NAME
#  about
# SOURCE
#
proc ::jmdict::about {} {
	variable ::jmdict::vers
	variable ::jmdict::jmdictVer

    set copyleft \
"tkjmdict $vers - Tcl/Tk application for searching JMdict\
\nCopyright (C) 2000-2012 Petteri Kettunen http://www.iki.fi/petterik/\ 
\nThis program is free software; you can redistribute it and/or modify\
it under the terms of the GNU General Public License as published by\
the Free Software Foundation; either version 2 of the License, or\
(at your option) any later version.\
\n\nThis program is distributed in the hope that it will be useful,\
but WITHOUT ANY WARRANTY; without even the implied warranty of\
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\
GNU General Public License for more details.\
\n\nYou should have received a copy of the GNU General Public License\
along with this program; if not, write to the Free Software\
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA\
\n\nThis package uses JMdict dictionary files. These files are the property of the Electronic Dictionary Research and Development Group, and are used in conformance with the Group's licence.\
\nSee: http://www.edrdg.org/edrdg/licence.html\
\nand http://www.csse.monash.edu.au/~jwb/jmdict.html\
\nJMdict version: $jmdictVer"
    ::jmdict::showNotice "$copyleft" 600 500
}

#****f* tkjmdict/exitProgram
# NAME
#  exitProgram
# SOURCE
#
proc ::jmdict::exitProgram {} {
    exit 0
}
#******

#****f* tkjmdict/_dbg
# NAME
#  _dbg
# SOURCE
#
proc _dbg {msg} {
    if {$::jmdict::debug} {
	puts stderr $msg
    }
}
#******

#****f* tkjmdict/sflgToggle
# NAME
#  sflgToggle
# SOURCE
#
# toggle search mode options
proc ::jmdict::sflgToggle {} {
    variable ::jmdict::sflg
    
    switch -- $sflg {
	0 {set sflg 1}
	1 {set sflg 2}
	default {set sflg 0}
    }
}
#******

#****f* tkjmdict/kbChange
# NAME
#  kbChange
# SOURCE
#
proc ::jmdict::kbChange {{i 0}} {
    variable ::jmdict::kb
    variable ::jmdict::kbid
    variable ::jmdict::kb0
    variable ::jmdict::kb1
    variable ::jmdict::kb2
    variable ::jmdict::kb3
    variable ::jmdict::kb4
    variable ::jmdict::kb5

    if {$i >= 0} {
	# change to given kbid, this is not very beautiful...
	if {$kbid != $i} {
	    array set kb [array get kb${i}]
	    set kbid $i
	}
    } else {
	# toggle kb
	switch $kbid {
	    0 {array set kb [array get kb1]; set kbid 1}
	    1 {array set kb [array get kb2]; set kbid 2}
	    2 {array set kb [array get kb3]; set kbid 3}
	    3 {array set kb [array get kb4]; set kbid 4}
	    4 {array set kb [array get kb5]; set kbid 5}
	    5 {array set kb [array get kb0]; set kbid 0}
	}
    }
    #set ::jmdict::kb(0,10) $kbid
    update
}
#******

#****f* tkjmdict/getc
# NAME
#  getc
# DESCRIPTION
#  Label clicked, get character associted with the label, if not 0,
#  insert it to the text entry.
# SOURCE
#
proc ::jmdict::getc {i} {
    set c $::jmdict::kb($i)
    scan $c %c val
    if {$val > 0} {
	#append ::jmdict::inp $c
	.inp.e insert [.inp.e index insert] $c
    } 
}
#******

#****f* tkjmdict/kb
# NAME
#  kb
# DESCRIPTION
#  Bring up Kana Board window, reposition if it already exists
# SOURCE
#
proc ::jmdict::kb {} {
    variable ::jmdict::font
    set w .kb
    if {![winfo exists $w]} {
	toplevel $w
	wm title $w "Kana Board"	
	# character labels
	for {set f 0} {$f != 6} {incr f} {
	    frame $w.f${f}
	    pack $w.f${f}
	    for {set i 0} {$i != 11} {incr i} {
		label $w.f${f}.l${i} -font $font -width 3 \
			-textvariable ::jmdict::kb(${f},${i}) \
			-bg white 
		bind $w.f${f}.l${i} <1> "::jmdict::getc ${f},${i}"
		bind $w.f${f}.l${i} <Any-Enter> \
			"$w.f${f}.l${i} configure -bg {#c0c0c0}"
		bind $w.f${f}.l${i} <Any-Leave> \
			"$w.f${f}.l${i} configure -bg white"
		pack  $w.f${f}.l${i} -side left
	    }
	}
	bind $w <Escape> "catch {destroy $w}"
	bind $w <Return> ::jmdict::search
	bind $w <Tab> {::jmdict::kbChange -1}
	bind $w <Key-1> {::jmdict::kbChange 0}
	bind $w <Key-2> {::jmdict::kbChange 1}
	bind $w <Key-3> {::jmdict::kbChange 2}
	bind $w <Key-4> {::jmdict::kbChange 3}
	bind $w <Key-5> {::jmdict::kbChange 4}
	bind $w <Key-6> {::jmdict::kbChange 5}
	bind $w <BackSpace> {
	    set ::jmdict::inp [string range $::jmdict::inp 0 end-1]
	}
    }
    ::jmdict::posWin $w kb
    focus -force $w
}
#******
    
#****f* tkjmdict/HandleStart
# NAME
#  HandleStart
# SOURCE
#
proc ::jmdict::HandleStart {name {attlist null}} {
    variable ::jmdict::g_lang 
    variable ::jmdict::entryok
    variable ::jmdict::n

    # bug? attlist may be set in the calling procedure
    # to zero-length string
    if {[string length $attlist] == 0} {
		set attlist null
    } 
    _dbg "Element start ==> $name has attributes $attlist"
    switch $name {
        entry {
            set entryok 1
        }
        ent_seq {
			set ::jmdict::elem $name
			_dbg "elem -> $name"
			incr n
        }
		keb -
		reb {
			if {$entryok} {
				set ::jmdict::elem $name
				_dbg "elem -> $name"
			}
		}
		gloss {
			if {$entryok} {
				if {$attlist == "null"} {
					set g_lang eng
				} else {
					set g_lang [lindex $attlist 1]
				}
				set ::jmdict::elem $name
				_dbg "GLOSS elem -> $name g_lang = $g_lang"
				# TODO: handle other languages...
			}
		}
    }
} 
#******

#****f* tkjmdict/HandleEntryData
# NAME
#  HandleEntryData
# FUNCTION
#  Check parsed entry and flush formatted data to file
# SOURCE
#
proc ::jmdict::HandleEntryData {} {
    variable ::jmdict::keb
    variable ::jmdict::reb
    variable ::jmdict::gloss
    variable ::jmdict::ptr
    variable ::jmdict::n
    variable ::jmdict::langs
    variable ::jmdict::glosses 
    variable ::jmdict::entryok
    variable ::jmdict::fps

    foreach l $langs {
		if {[info exists gloss($l)]} {
			_dbg "XXXX $l "
			incr glosses($l)
			# gloss for the given lang is found
			if {[info exists keb(0)]} {			
				puts $fps($l) "$keb(0) {$reb(0)} {$gloss($l)}"
			} else {
				# kanji entry does not exist
				puts $fps($l) "{$reb(0)} {$gloss($l)}"
			}
			unset gloss($l)
		}
    }
    if {![info exists reb(0)] && ![info exists reb(0)]} {
		puts "panic! reb and keb missing $n"
    }
    if {[info exists keb(0)] && ![info exists reb(0)]} {
		puts "panic! keb without reb missing $n"
    }
    catch {unset keb(0)} ;# BUGGY???
    catch {unset reb(0)}
} 
#******

#****f* tkjmdict/HandleEnd
# NAME
#  HandleEnd
# SOURCE
#
proc ::jmdict::HandleEnd {name {attlist null}} {
    variable ::jmdict::entryok
    _dbg "Element end ==> $name has attributes $attlist"
    switch $name {
		entry {
			set entryok 0
			_dbg "ptr -> $::jmdict::ptr"
            ::jmdict::HandleEntryData
		}
    }    
} 
#******

#****f* tkjmdict/HandleText
# NAME
#  HandleText
# BUGS
#  This routine has certain whitespace problem(s)
#  Should read tclxml parser docs better.
# SOURCE
#
proc ::jmdict::HandleText {data} {
    variable ::jmdict::elem
    variable ::jmdict::kanji
    variable ::jmdict::ptr
    variable ::jmdict::g_lang

    set len [string length $data]
    if { "\n" != $data && $len > 0} {	
	_dbg "data $len = $data"
	_dbg "elem = $elem"
	if {$elem != 0} {	    
	    _dbg "$elem -> $data"
	    switch $elem {
                ent_seq {
                    set ::jmdict::ent_seq $data
                }
		keb {
		    set ::jmdict::keb($ptr) $data
		    set elem 0
		}
		reb {
		    lappend ::jmdict::reb($ptr) $data
		    set elem 0
		}
		gloss {
		    # g_lang is set in ::jmdict::HandleStart
		    lappend ::jmdict::gloss($g_lang) $data
		    set elem 0
		}
	    }
	}
    }
}
#******

#****f* tkjmdict/HandlePI
# NAME
#  HandlePI
# SOURCE
#
proc ::jmdict::HandlePI {target data} {
    _dbg "Processing instruction ==> $target $data"
}
#******

#****f* tkjmdict/HandleXMLDecl
# NAME
#  HandleXMLDecl 
# SOURCE
#
proc ::jmdict::HandleXMLDecl {version encoding standalone} {
    _dbg "XML Declaration ==> version $version encoding $encoding standalone $standalone"
}
#******

#****f* tkjmdict/HandleComment
# NAME
#  HandleComment
# DESCRIPTION
#  <!-- JMdict created: 2012-01-20 -->
# SOURCE
#
proc ::jmdict::HandleComment {data} {
    _dbg "Comment ==> $data"
	if {[string match "*JMdict created:*" $data]} {
        set ::jmdict::jmdictVer [string range $data [expr [string last ":" $data] + 2] end]
    }
}
#******

#****f* tkjmdict/parseJMdict
# NAME
#  parseJMdict
# DESCRIPTION
#  Parse JMdict XML file 
# SYNOPSIS
#  ::jmdict::parseJMdict xmfile outbody
#    xmlfile - path to jmdict file
#    outbody - prefix for parsed output files
# SOURCE
#
proc ::jmdict::parseJMdict {xml out} {
    global tcl_version
    variable ::jmdict::keb
    variable ::jmdict::reb
    variable ::jmdict::gloss
    variable ::jmdict::ptr
    variable ::jmdict::n
    variable ::jmdict::langs
    variable ::jmdict::glosses 
    variable ::jmdict::entryok
    variable ::jmdict::fps

    if {$tcl_version < 8.5} {
		puts stderr "Tcl version 8.1 or newer is required!"
		puts stderr "This version of Tcl is [info patchlevel]"
		exit 1
    }
    if {[catch {package require tdom}]} {
		puts stderr "could not load tdom package"
		exit 1
    }
    if {[catch {set f [open $xml r]}]} {
        puts stderr "can not open file '$xml'"
        exit 1
    }
    fconfigure $f -encoding utf-8    

    foreach l $langs {
		set o [open "${out}_${l}.bin" w]
		fconfigure $o -encoding utf-8
		set fps($l) $o
		set glosses($l) 0
    }

    set n 0 ;# incremented in ::jmdict::HandleStart

    # some of these configs are not needed, should work on this
    set parser [xml::parser]
    #$parser configure -validate yes
    #$parser configure -doctypecommand HandleDocType
    #$parser configure -xmldeclcommand ::jmdict::HandleXMLDecl
    $parser configure -elementstartcommand ::jmdict::HandleStart
    $parser configure -elementendcommand ::jmdict::HandleEnd
    $parser configure -characterdatacommand ::jmdict::HandleText
    #$parser configure -processinginstructioncommand ::jmdict::HandlePI
    $parser configure -commentcommand ::jmdict::HandleComment
    #$parser configure -defaultexpandinternalentities 0
    #$parser configure -paramentityparsing notstandalone
    $parser configure -final 0
    #$parser configure -parameterentitydeclcommand ::jmdict::myNull
    #$parser configure -entityreferencecommand ::jmdict::myNull
    #$parser configure -externalentitycommand ::jmdict::myNull
    #$parser configure -errorcommand ::jmdict::myNull
	while {[gets $f l] >= 0} {
		$parser parse $l
	}		

	#$parser parse [read $f]
	$parser reset
	$parser free
 	
    close $f
    foreach l [array names fps] {
		close $fps($l)
    }
}
#******

#****f* tkjmdict/dictEntry
# NAME
#  dictEntry
# DESCRIPTION
#  Construct dictionary memory element from given arguments
# SOURCE
#
# here the ptr is running index
proc ::jmdict::dictEntry {args} {
    variable ::jmdict::keb
    variable ::jmdict::reb
    variable ::jmdict::gloss
    variable ::jmdict::ptr

    if {[llength $args] == 3} {
	set keb($ptr) [lindex $args 0]
	set reb($ptr) [lindex $args 1]
	set gloss($ptr) [lindex $args 2]
    } else {
	set reb($ptr) [lindex $args 0]
	set gloss($ptr) [lindex $args 1]
    }
    incr ptr
}
#******

#****f* tkjmdict/dictRead
# NAME
#  dictRead
# DESCRIPTION
#  Read dictionary from file to memory
# SOURCE
#
proc ::jmdict::dictRead {dict} {
    variable ::jmdict::maxEntries
    variable ::jmdict::dictDir
    variable ::jmdict::loadT
    ::jmdict::busy
    set loadT [time {
		.t delete 1.0 end
		set fname [file join $dictDir jmdict_${dict}.bin]
		if {[catch {set f [open $fname r]}]} {
			.t insert end "error in opening $fname\n"
		} else {
			fconfigure $f -encoding utf-8   
			set i 0
			while {[gets $f l] >= 0} {
				catch {eval "::jmdict::dictEntry $l"}
				if {[incr i] == $maxEntries} {
					break
				}		
			}
			close $f
		}
    }
			  ]
    set loadT [lindex $loadT 0]
	.t insert end "Dictionary `$dict', $i entries, ([expr {$loadT/1000000.0}] sec)\n"
    ::jmdict::busy
}
#******

#****f* tkjmdict/search
# NAME
#  search
# SOURCE
# 
proc ::jmdict::search {} {
    variable ::jmdict::n 
    variable ::jmdict::inp
    variable ::jmdict::resIndex
    variable ::jmdict::res
    variable ::jmdict::matches
    variable ::jmdict::searchT
    variable ::jmdict::searchN

    if {![catch {set s [.t get sel.first sel.last]}]} {
		# user has selected something from the text, use it as a search key
		set inp $s
    }
    # get rid of trailing/preceeding space(s)
    set inp [string trimright $inp]
    set inp [string trimleft $inp]
    if {[string length $inp] == 0} {
		return
    }
    ::jmdict::busy
    .t delete 1.0 end
    set n 0
    set t [time ::jmdict::doSearch]
    incr searchT [lindex $t 0]
    incr searchN
    # write the result
    set matches $n
    if {$n} {
		foreach i [lsort -integer $resIndex] {
			set x $res($i,jp)
			set p [.t index insert]
			.t insert end $x\n
			.t tag add t $p "$p + [string length $x] chars" 
			foreach g $res($i,g) {
				.t insert end "   $g\n"
			}
			#.t insert end \n
		}
    }
    if {$n} {
		# put focus to the text so user can scroll up/down the results
		focus -force .t
		.t mark set insert 1.0
    } else {
		# focus so that user is ready for new search
		focus -force .inp.e
    }
    ::jmdict::busy
}
#******

#****f* tkjmdict/doSearch
# NAME
#  doSearch
# DESCRIPTION
#  Search dictionary
# SOURCE
#
proc ::jmdict::doSearch {} {
    variable ::jmdict::inp
    variable ::jmdict::keb
    variable ::jmdict::reb
    variable ::jmdict::gloss
    variable ::jmdict::sflg
    variable ::jmdict::n
    variable ::jmdict::res
    variable ::jmdict::resIndex
    variable ::jmdict::maxMatches

    catch {unset res}
    catch {unset resIndex}
    # get the unicode value of the first string and decide what
    # field to search
    scan [string index $inp 0] %c val
    # the f-flag code should go to ::jmdict::search
    if {$val < 0x3000} {
		# assume Latin-1 input, search glosses
		set f 1
    } elseif {($val >= 0x3000 && $val <= 0x30FF) || \
				  ($val > 0xFF00 && $val < 0xFFFF)} {
		# kana page or JASCII that in Unicode is the same as 
		# full-width latin letters, page FF00
		set f 0
    } else {
		# assume kanji input
		set f 2
    }
    if {$f == 2} {
		# search only elements that has kanji defined
		set s [array startsearch keb]
    } else {    
		# reb has same elements as gloss
		set s [array startsearch reb]
    }
    # ready to go, search...
    while {1} {
		if {$f == 2} {  
			set e [array nextelem keb $s]
		} else {
			set e [array nextelem reb $s]
		}
		if {$e == ""} {
			# reached end of the hash, get out of the loop
			break
		} else {
			# get the data from the hash element
			switch $f {
				0 {set d $reb($e)}
				1 {set d $gloss($e)}
				default {set d $keb($e)}
			}
			# sflg: 0->start of the word, 1->substring, 2->whole word
			switch -- $sflg {
				0 {set r [lsearch -glob -nocase $d $inp*]}
				1 {set r [lsearch -glob -nocase $d *$inp*]}
				default {set r [lsearch -exact -nocase $d $inp]}
			}
			if {$r >= 0} {
				if {[info exists keb($e)]} {	
					# there is kanji defined in the dict entry
					set x "$keb($e) $reb($e)"
				} else {
					# only kana element
					set x "$reb($e)"
				}
				# put results to res hash (array), the sorting is done
				# in ::jmdict::search after the whole search is ready
				set res($e,jp) $x
				set res($e,g) $gloss($e)
				lappend resIndex $e
				# do not exhaust the poor text widget, limit matches
				if {[incr n] == $maxMatches} {
					break
				}
			}
		}
    }
    # seach done, clean up
    if {$f == 2} {
		array donesearch keb $s    
    } else {
		array donesearch reb $s    
    }
}
#******

#****f* tkjmdict/busy
# NAME
#  busy
# DESCRIPTION
#  Toggle busy icon
# SOURCE
#
proc ::jmdict::busy {} {
    variable ::jmdict::busy 
    variable ::jmdict::busyBg
    if {$busy} {
		.frameopt.busy configure -fg $busyBg
		set busy 0
    } else {
		.frameopt.busy configure -fg black
		set busy 1
    } 
    update
}
#******

#****f* tkjmdict/viewUnicode
# NAME
#  viewUnicode
# DESCRIPTION
#  Read Unicode values from selected text and display in hex.
# SOURCE
#
proc ::jmdict::viewUnicode {} {
    set txt [selection get]
    if {[string length $txt]} {
		set u ""
		foreach c [split $txt ""] {
			scan $c %c v
			append u "0x[format {%04.4X} $v] $c\n"
		}
		tk_messageBox -type ok -message $u
    }
}
#******

#****f* tkjmdict/clipBoard
# NAME
#  clipBoard
# DESCRIPTION
#  Clipboard functions. Seems to work from menus but key bindings
#  make trouble.
# SOURCE
#
proc ::jmdict::clipBoard {what} {
    set f [focus]
    if {$f == {.inp.e} || $f == {.t}} {
		switch -- $what {
			cut {tk_textCut $f}
			copy {tk_textCopy $f}
			paste {tk_textPaste $f}
		}
    }
}
#******


#****f* tkjmdict/clearAll
# NAME
#  clearAll
# DESCRIPTION
#  Clear text field and variables associated to search
# SOURCE
#
proc ::jmdict::clearAll {} {
    catch {.t delete 1.0 end}
    set ::jmdict::inp {}
    set ::jmdict::matches {}
}
#******

#****f* tkjmdict/initUI
# NAME
#  initUI
# DESCRIPTION
#  Init GUI
# SOURCE
#
proc ::jmdict::initUI {} {
    global tk_version
    variable ::jmdict::langNames
    variable ::jmdict::availableDicts
	
    # here we have to check that Tk is available
    if {![info exist tk_version]} {
		puts stderr "Please use wish to run this application"
		# try to load tk dynamically
		global tcl_version 
		if {[catch {regsub {\.} $tcl_version {} v; load tk${v}}]} {
			puts stderr "could not load tk${v}"
			exit 1
		}
    }
    if {$tk_version < 8.5} {
		tk_messageBox -type ok -message "Tcl/Tk version 8.5 or newer is needed to run this application.\nBinary [info nameofexecutable] is ${tk_version}.\nPlease get an upgrade from http://tcl.activestate.com/.\nPress ok to exit this application"
		exit 1
    }
    ::jmdict::initUIVars
    frame .fmenus -bd 2 -relief raised
    pack .fmenus -fill x
    # file menu
    menubutton .fmenus.file -text File -menu .fmenus.file.menu
    menu .fmenus.file.menu -tearoff 0
    .fmenus.file.menu add command -label Quit -accelerator Ctrl-Q \
	    -command ::jmdict::exitProgram
    # edit menu
    menubutton .fmenus.edit -text Edit -menu .fmenus.edit.menu
    menu .fmenus.edit.menu -tearoff 0
    .fmenus.edit.menu add command -label Cut -accelerator Ctrl-X \
	    -command {::jmdict::clipBoard cut}
    .fmenus.edit.menu add command -label Copy -accelerator Ctrl-C \
	    -command {::jmdict::clipBoard copy}
    .fmenus.edit.menu add command -label Paste -accelerator Ctrl-V \
	    -command {::jmdict::clipBoard paste}
    .fmenus.edit.menu add command -label Clear \
	    -command {::jmdict::clearAll}
    # options menu
    menubutton .fmenus.options -text Options -menu .fmenus.options.menu
    menu .fmenus.options.menu -tearoff 0
    #.fmenus.options.menu add command -label Search 
	#    -accelerator Ctrl-S -command ::jmdict::search
    .fmenus.options.menu add command -label {Insert kana} \
	    -accelerator Ctrl-J -command ::jmdict::kb
    .fmenus.options.menu add command -label Font \
	    -command ::jmdict::selectFont
    .fmenus.options.menu add cascade -label {Font Size} \
	    -menu .fmenus.options.menu.fsize
    menu .fmenus.options.menu.fsize -tearoff 0
    .fmenus.options.menu.fsize add radio -label 10 \
	    -variable ::jmdict::newFontSize -value 10    
    .fmenus.options.menu.fsize add radio -label 12 \
	    -variable ::jmdict::newFontSize -value 12    
    .fmenus.options.menu.fsize add radio -label 14 \
	    -variable ::jmdict::newFontSize -value 14
    .fmenus.options.menu.fsize add radio -label 18 \
	    -variable ::jmdict::newFontSize -value 18
    .fmenus.options.menu.fsize add radio -label 24 \
	    -variable ::jmdict::newFontSize -value 24
    .fmenus.options.menu.fsize add radio -label 36 \
	    -variable ::jmdict::newFontSize -value 36
    .fmenus.options.menu.fsize invoke 1 
    .fmenus.options.menu add cascade -label Language \
	    -menu .fmenus.options.menu.lang
    menu .fmenus.options.menu.lang -tearoff 0
    foreach i $availableDicts {
		.fmenus.options.menu.lang add radio \
			-label $langNames($i) -variable ::jmdict::newLang \
			-value [lsearch -exact $availableDicts $i]
    }
    # langPtr is set in ::jmdict::main    
    .fmenus.options.menu.lang invoke $::jmdict::langPtr
    #.fmenus.options.menu.lang add radio -label \u65E5\u672C\u8A9E 
    #-variable ::jmdict::newLang -value 2
    # Help menu
    menubutton .fmenus.help -text Help -menu .fmenus.help.menu
    menu .fmenus.help.menu -tearoff 0
    .fmenus.help.menu add command -label About -accelerator Ctrl+H \
	    -command ::jmdict::about
    pack .fmenus.file .fmenus.edit .fmenus.options -side left -padx 10
    pack .fmenus.help -side right -padx 10    
    # text
    frame .frame
    pack  .frame -expand yes -fill both -padx 1 -pady 1
    text .t -height $::jmdict::textRows \
	    -width $::jmdict::textCols -wrap none \
	    -xscrollcommand ".xscroll set" \
	    -yscrollcommand ".yscroll set" \
	    -setgrid 1 -highlightthickness 0 -pady 2 -padx 3 \
	    -font $::jmdict::font \
	    -selectbackground {#c0c0c0} 
    scrollbar .xscroll -command ".t xview" \
	    -highlightthickness 0 -orient horizontal
    scrollbar .yscroll -command ".t yview" \
	    -highlightthickness 0 -orient vertical    
    # search result listbox + scrolls (experimental, maybe for later use)
    #listbox .lst -yscroll {.lstscr set} -xscroll {.lstscrx set} 
    #-setgrid 1 -height 12 -width 20 -bg white
    #scrollbar .lstscr -command {.lst yview}
    #scrollbar .lstscrx -command {.lst xview} -orient horizontal
    # search frame/entry
    frame .inp 
    entry .inp.e -textvariable ::jmdict::inp -font $::jmdict::font \
	    -selectbackground {#c0c0c0} 
    button .inp.b -text ">>>" -command ::jmdict::search
    # search options
    frame .frameopt
    #label .frameopt.l -text Search options:
    radiobutton .frameopt.r1 -text {start of word} \
	    -variable ::jmdict::sflg -relief flat -value 0
    radiobutton .frameopt.r2 -text {substring} \
	    -variable ::jmdict::sflg -relief flat -value 1
    radiobutton .frameopt.r3 -text {whole word} \
	    -variable ::jmdict::sflg -relief flat -value 2
    # match label, width depends on maxMatches
    label .frameopt.matches -width 6 -textvariable ::jmdict::matches
    grid .t -in .frame -padx 1 -pady 1 \
	    -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid .yscroll -in .frame -padx 1 -pady 1 \
	    -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news
    #grid .lst -in .frame -padx 1 -pady 1 
    #	    -row 0 -column 2 -rowspan 1 -columnspan 1 -sticky news    
    #grid .lstscr -in .frame -padx 1 -pady 1 
    #-row 0 -column 3 -rowspan 1 -columnspan 1 -sticky news
    grid .xscroll -in .frame -padx 1 -pady 1 \
	    -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
    #grid .lstscrx -in .frame -padx 1 -pady 1 
    #-row 1 -column 2 -rowspan 1 -columnspan 1 -sticky news
    grid .inp -in .frame -padx 1 -pady 5 \
	    -row 2 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid .frameopt -in .frame -padx 1 -pady 1 \
	    -row 3 -column 0 -rowspan 1 -columnspan 1 -sticky news
    grid rowconfig    .frame 0 -weight 1 -minsize 0
    grid columnconfig .frame 0 -weight 1 -minsize 0
    pack .inp.e -side left -expand 1 -fill x
    pack .inp.b -side right -padx 5
    label .frameopt.busy -bitmap hourglass    
    pack .frameopt.r1 .frameopt.r2 .frameopt.r3 -side left
    pack .frameopt.busy .frameopt.matches -side right
    set ::jmdict::busyBg [.frameopt.busy cget -bg]
    .frameopt.r1 invoke
    # window settings and bindings
	wm iconify .
    wm title . tkjmdict
    bind .inp.e <Return> ::jmdict::search
    bind all <Control-h> ::jmdict::about
    bind all <Control-I> ::jmdict::insertFile
    bind all <Control-j> ::jmdict::kb
    bind all <Control-m> ::jmdict::sflgToggle
    bind all <Control-n> {focus -force .inp.e}
    bind all <Control-q> ::jmdict::exitProgram
    bind all <Control-s> ::jmdict::focussearch
    bind all <Control-S> ::jmdict::saveTextAs
    #bind all <Control-p> ::jmdict::busy
    bind all <Control-u> ::jmdict::viewUnicode
    bind all <Control-t> ::jmdict::showStatistics
    bind all <Control-T> {
		# small benchmark
		# make dummy search first to make sure that all the bytecode
		# is properly compiled, this also sets options...
		set ::jmdict::inp abcdefghijklmn
		::jmdict::search
		::jmdict::busy
		set ::jmdict::searchT 0
		set ::jmdict::searchN 0
		foreach i [list cat dog sheep space {vanha harakka} rautalapio \
					   puhelin {mobile phone} shop a] {
			set ::jmdict::inp $i
			update
			incr ::jmdict::searchT [lindex [time ::jmdict::doSearch] 0]
			incr ::jmdict::searchN
		}
		::jmdict::showStatistics
		::jmdict::busy
		set ::jmdict::inp {}
    }
    wm protocol . WM_DELETE_WINDOW {
		::jmdict::exitProgram
    }
    # tag i.e. style for kanji/kana entries, used in ::jmdict::search
    .t tag configure t -foreground blue
	# set the default search option
    .frameopt.r2 select
}
#******

#****f* tkjmdict/activateTraces
# NAME
#  activateTraces
# DESCRIPTION
#  Define hooks for functions that are called when variables are changed
# SOURCE
#
proc ::jmdict::activateTraces {} {
    trace variable ::jmdict::newLang w ::jmdict::changeLang
    trace variable ::jmdict::newFontSize w ::jmdict::changeFont
}
#******

#****f* tkjmdict/checkForDicts
# NAME
#  checkForDicts
# DESCRIPTION
#  Search for dictionary files from filesystem.
# SOURCE
#
proc ::jmdict::checkForDicts {d} {
    set res 0
    foreach i $::jmdict::langs {
		set f [file join $d jmdict_${i}.bin]
		if {[file exists $f] && [file readable $f]} {
			incr res
		}
    }
    return $res
}
#******

#****f* tkjmdict/getDicts
# NAME
#  getDicts
# DESCRIPTION
#  Get list of dictionary files.
# SOURCE
#
proc ::jmdict::getDicts {} {
    set res {}
    foreach i $::jmdict::langs {
		set f [file join $::jmdict::dictDir jmdict_${i}.bin]
		if {[file exists $f] && [file readable $f]} {
			lappend res $i
		}
    }
    return $res
}
#******

#****f* tkjmdict/main
# NAME
#  main
# DESCRIPTION
#  Main entry point
# SOURCE
#

proc ::jmdict::focussearch {} {
    focus -force .inp.e
	# FIXME select text in search field if entered
}

proc ::jmdict::readJMdictVersion {} {
	variable ::jmdict::jmdictVer
	variable ::jmdict::dictDir
	
	set f [file join $dictDir jmdict.log]
    if {![catch {set fp [open $f r]}] && [gets $fp vers] >= 0} {
		set jmdictVer [string trimleft [string trimright $vers]]
		close $fp
    }
}

proc ::jmdict::main {} {
    global argv
    global env
    variable ::jmdict::freeWrap
    variable ::jmdict::jmdictVer
    variable ::jmdict::vers

    # for development only...
    if {[info exists env(DEBUG)] && $env(DEBUG) != 0} {
		set ::jmdict::maxEntries 15
    }
    set freeWrap [info exists ::_freewrap_contents]
    set lang {}
    foreach i $argv {
		if {[string compare $i -parse] == 0 && \
				[llength $argv] == 2} {
			set t [clock seconds]
			::jmdict::parseJMdict [lindex $argv 1] jmdict
			set t [expr {[clock seconds] - $t}]
			set f [open jmdict.log w]
			puts $f "$jmdictVer"
			puts $f "processing time $t seconds"
			puts $f "total $::jmdict::n entries"
			foreach l [lsort [array names ::jmdict::glosses]] {
				puts $f "$l $::jmdict::glosses($l)"
			}
			close $f
			exit 0
		} elseif {[string compare $i -lang] == 0 && [llength $argv] == 2} {
			set lang [lindex $argv 1]
		}
    }
    # horrible, horrible, work on this...
    if {$::jmdict::dictDir == "" && $freeWrap == 0} {
		set dir /usr/share/tkjmdict
		if {[checkForDicts $dir] > 0} {
			set ::jmdict::dictDir $dir 
		} else {
			# dictionary directory not give in the command line:
			# (1) try the same dir from which this script was loaded
			if {[info script] == ""} {
				set dir [file dirname [info nameofexecutable]]
			} else {
				set dir [file dirname [info script]]
			}
			if {[checkForDicts $dir] > 0} {
				set ::jmdict::dictDir $dir
			} elseif {[checkForDicts [file join $dir ../lib]] > 0} {
				set ::jmdict::dictDir [file join $dir ../lib]
			} elseif {[checkForDicts [file join [pwd]]] > 0} {
				set ::jmdict::dictDir [file join [pwd]]
			} else {
				tk_messageBox -type ok \
					-message {Could not find any dictionaries!}
				# rather cruel way, but leave it like this until
				# there is "load dict" feature implemented.
				::jmdict::exitProgram
			}
		}
    } 

    # with freeWrap dictDir can be null
    if {$::jmdict::dictDir != "" || $freeWrap} {
		# dictDir not given in the command line
		# well, the flag is still missing...	
		set ::jmdict::availableDicts [::jmdict::getDicts]
		if {$lang != "" && \
				[lsearch -exact $::jmdict::availableDicts $lang] >= 0} {
			# user-requested lang is available, lang ok... 
			# ..but this is horrible
			set ::jmdict::langPtr [lsearch -exact $::jmdict::langs $lang]
		} else {
			# default to first dict from the available list
			set lang [lindex $::jmdict::availableDicts 0]
			set ::jmdict::langPtr 0
		}
    }

	::jmdict::readJMdictVersion

    set startupMsg "tkjmdict $vers / JMdict $jmdictVer\n\nCopyright (C) 2000-2012 Petteri Kettunen\n\ntkjmdict comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions; type Ctrl-H for details. \n\nThe dictionary data is based solely on the JMdict
(Japanese Multilangual dictionary). Type Ctrl-H for terms of usage of this data."

    wm iconify .
    ::jmdict::showNotice "$startupMsg" 500 500 
    focus -force .notice

    ::jmdict::initUI
    ::jmdict::dictRead $lang
    ::jmdict::activateTraces

    # ready to go
    after 1500 dox
}
#******

proc dox {} {
    # get rid of the notice window
    catch {destroy .notice}
    # focus to input field
    focus -force .inp.e
	wm deiconify .
}

#****f* tkjmdict/prog_entry
# NAME
#  prog_entry
# DESCRIPTION
#  Program entry point
# SEE ALSO
#  ::jmdict::main
# SOURCE
#
::jmdict::main
tkwait variable _wait_for_a_while_
exit 0 ;# never reached
#******
